﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Collections.Specialized;
using LitJson;

namespace BtLibs.Http
{
    public class HttpClient
    {
        private CookieContainer cookieContainer;
        private Encoding encoding = Encoding.UTF8;
        public Encoding Encoding { get { return encoding; } set { encoding = value; } }
        public HttpClient()
        {
            this.cookieContainer = new CookieContainer();
        }

        public JsonData GetJson(string url, JsonData arg)
        {
            string response = GetString(url, JsonToKeyValue(arg));
            return string.IsNullOrEmpty(response) ? null : JsonMapper.ToObject(response);
        }
        public string GetString(string url, JsonData arg)
        {
            return GetString(url, JsonToKeyValue(arg));
        }
        public JsonData GetJson(string url, KeyValues kvs)
        {
            string response = GetString(url, kvs.Values);
            return string.IsNullOrEmpty(response) ? null : JsonMapper.ToObject(response);
        }
        public string GetString(string url, KeyValues kvs)
        {
            return GetString(url, kvs.Values);
        }
        private string GetString(string url, List<KeyValue> args)
        {
            url = url + "?" + BuildRequestString(args);
            HttpWebRequest request = NewFormRequest(url);
            request.Method = "GET";
            using (WebResponse response = request.GetResponse())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding))
                {
                    return reader.ReadToEnd();
                }
            }
        }
        public Stream GetStream(string url, KeyValues args = null)
        {
            if(args != null)
            {
                url = url + "?" + BuildRequestString(args.Values);
            }
            HttpWebRequest request = NewFormRequest(url);
            request.Method = "GET";
            using (WebResponse response = request.GetResponse())
            {
                Stream stream = response.GetResponseStream();
                MemoryStream buffer = new MemoryStream();
                byte[] bytes = new byte[1 << 20];
                int count = 0;
                while ((count = stream.Read(bytes, 0, 1 << 20)) > 0)
                {
                    buffer.Write(bytes, 0, count);
                }
                //response.GetResponseStream().Read(bytes, 0, (int)response.GetResponseStream().Length);
                //return new MemoryStream(bytes);
                return new MemoryStream(buffer.ToArray());
            }
        }

        public JsonData PostJson(string url, JsonData arg)
        {
            string response = PostString(url, JsonToKeyValue(arg));
            return string.IsNullOrEmpty(response) ? null : JsonMapper.ToObject(response);
        }
        public string PostString(string url, JsonData arg)
        {
            return PostString(url, JsonToKeyValue(arg));
        }
        public JsonData PostJson(string url, KeyValues kvs)
        {
            string response = PostString(url, kvs.Values);
            return string.IsNullOrEmpty(response) ? null : JsonMapper.ToObject(response);
        }
        public string PostString(string url, KeyValues kvs)
        {
            return PostString(url, kvs.Values);
        }
        private string PostString(string url, List<KeyValue> args)
        {
            string requestContent = BuildRequestString(args);
            byte[] requestBytes = Encoding.GetBytes(requestContent);
            HttpWebRequest request = NewFormRequest(url);
            request.Method = "POST";
            Stream stream = request.GetRequestStream();
            stream.Write(requestBytes, 0, requestBytes.Length);
            using (WebResponse response = request.GetResponse())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        public string UploadFile(string url, byte[] imgBytes, string fileType, string filename = "binary")
        {
            HttpWebRequest request = NewRequest(url);
            request.Method = "POST";
            string boundary = "--AGPOWKDJGH";
            string contentType = "multipart/form-data;boundary=" + boundary;
            request.ContentType = contentType;
            request.KeepAlive = true;

            string strBegin = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"file\";filename=\""
                + filename + "\"\r\nContent-Type=\"" + fileType + "\"\r\n\r\n";
            string str1 = "\r\n--" + boundary + "--\r\n";
            MemoryStream mstream = new MemoryStream();
            byte[] str0Bytes = Encoding.UTF8.GetBytes(strBegin);
            byte[] strEndBytes = Encoding.UTF8.GetBytes(str1);
            mstream.Write(str0Bytes, 0, str0Bytes.Length);
            mstream.Write(imgBytes, 0, imgBytes.Length);
            mstream.Write(strEndBytes, 0, strEndBytes.Length);
            request.GetRequestStream().Write(mstream.ToArray(), 0, ((int)mstream.Length));
            using (WebResponse response = request.GetResponse())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        private HttpWebRequest NewFormRequest(string url)
        {
            HttpWebRequest request = NewRequest(url);
            request.ContentType = "application/x-www-form-urlencoded";
            return request;
        }
        private HttpWebRequest NewRequest(string url)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.CookieContainer = cookieContainer;
            return request;
        }

        public static JsonData StringToJson(string s)
        {
            return JsonMapper.ToObject(s);
        }
        public static KeyValues JsonToKeyValue(JsonData json)
        {
            return JsonToKeyValue("", json);
        }
        public static KeyValues JsonToKeyValue(string namePrefix, JsonData json)
        {
            KeyValues kvs = new KeyValues();
            if (json.IsObject)
            {
                foreach (KeyValuePair<string, JsonData> item in json)
                {
                    string key = string.IsNullOrEmpty(namePrefix) ? item.Key : namePrefix + "." + item.Key;
                    kvs.Add(JsonToKeyValue(key, item.Value));
                }
            }
            else if (json.IsArray)
            {
                foreach (JsonData item in json)
                {
                    kvs.Add(JsonToKeyValue(namePrefix, item));
                }
            }
            else
            {
                kvs.Add(namePrefix, json.ToString());
            }
            return kvs;
        }

        private string BuildRequestString(List<KeyValue> args)
        {
            List<string> argTxts = new List<string>();
            foreach (KeyValue kv in args)
            {
                argTxts.Add(string.Format("{0}={1}", Uri.EscapeDataString(kv.Key), Uri.EscapeDataString(kv.Value)));
            }
            return string.Join("&", argTxts);
        }
    }
}
